package com.lucenten.collect.gnss.handler.tools;

import cn.quevo.common.exception.CustomException;
import cn.quevo.common.lang.NumberUtils;
import cn.quevo.common.lang.StringUtils;
import cn.quevo.common.utils.BeanUtils;
import cn.quevo.core.spring.util.SpringUtil;
import com.lucenten.collect.gnss.entity.GnssFile;
import com.lucenten.collect.gnss.entity.SatelliteStation;
import com.lucenten.collect.gnss.entity.TecpTecl;
import com.lucenten.collect.gnss.entity.trans.TecpTeclTrans;
import com.lucenten.collect.gnss.enums.PathFileType;
import com.lucenten.collect.gnss.handler.files.CAzimuthElevation;
import com.lucenten.collect.gnss.handler.files.GAzimuthElevation;
import com.lucenten.collect.gnss.handler.files.NAzimuthElevation;
import com.lucenten.collect.gnss.handler.files.PathFiles;
import com.lucenten.collect.gnss.service.SatelliteStationService;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class OFileTools {

    private static void initXyz(TecpTeclTrans tecpTeclTrans, GnssFile gnssFile, SatelliteStationService satelliteStationService) {
        SatelliteStation satelliteStation = gnssFile.getStation();
        if (satelliteStation == null) {
            return;
        }
        boolean update = false;
        if (StringUtils.isBlank(tecpTeclTrans.getX()) && !StringUtils.isBlank(satelliteStation.getX())) {
            tecpTeclTrans.setX(satelliteStation.getX());
        }
        if (StringUtils.isBlank(tecpTeclTrans.getY()) && !StringUtils.isBlank(satelliteStation.getY())) {
            tecpTeclTrans.setY(tecpTeclTrans.getY());
        }
        if (StringUtils.isBlank(tecpTeclTrans.getZ()) && !StringUtils.isBlank(satelliteStation.getZ())) {
            tecpTeclTrans.setZ(satelliteStation.getZ());
        }
        if (StringUtils.isBlank(satelliteStation.getX()) && !StringUtils.isBlank(tecpTeclTrans.getX())) {
            update = true;
            satelliteStation.setX(tecpTeclTrans.getX());
        }
        if (StringUtils.isBlank(satelliteStation.getY()) && !StringUtils.isBlank(tecpTeclTrans.getY())) {
            update = true;
            satelliteStation.setY(tecpTeclTrans.getY());
        }
        if (StringUtils.isBlank(satelliteStation.getZ()) && !StringUtils.isBlank(tecpTeclTrans.getZ())) {
            update = true;
            satelliteStation.setZ(tecpTeclTrans.getZ());
        }
        if (update) {
//            SatelliteStationService satelliteStationService = SpringUtil.getBean("satelliteStationService");
            satelliteStationService.update(satelliteStation);
        }
    }
    /**
     * 解析文件头部信息
     *
     * @param tecpTeclTrans TECP数据存储对象
     * @param lines         所有行
     * @param index         当前行索引
     * @return 继续读取后的行数
     */
    public static int analysisHeader(TecpTeclTrans tecpTeclTrans, List<String> lines, int index, boolean isVerTow, GnssFile gnssFile, SatelliteStationService satelliteStationService) {
        int begin = isVerTow ? 6 : 7;
        int end = isVerTow ? 60 : 40;
        int size = isVerTow ? 6 : 4;
        String sub = "";
        for (; index < lines.size(); index++) {
            String line = lines.get(index);
            if (line.contains("APPROX POSITION XYZ")) {
                tecpTeclTrans.setX(NumberUtils.toDouble(line.substring(0, 14).trim()));
                tecpTeclTrans.setY(NumberUtils.toDouble(line.substring(14, 28).trim()));
                tecpTeclTrans.setZ(NumberUtils.toDouble(line.substring(28, 42).trim()));
                initXyz(tecpTeclTrans, gnssFile,satelliteStationService);
                if (tecpTeclTrans.getX() == 0 || tecpTeclTrans.getY() == 0 || tecpTeclTrans.getZ() == 0) {
                    throw new CustomException(6100, "XYZ 为空或为0,无需继续读取");
                }
                continue;
            }
            if ((isVerTow && line.contains("# / TYPES OF OBSERV"))
                    || (line.contains("SYS / # / OBS TYPES"))) {
                tecpTeclTrans.setObsTypeNum(NumberUtils.toInt(isVerTow ? line.substring(0, 6).trim() : line.substring(4, 6).trim()));
                StringBuilder obsType = new StringBuilder(line.substring(begin, end));
                List<String> obsTypeList = new ArrayList<>(tecpTeclTrans.getObsTypeNum());
                if (tecpTeclTrans.getObsTypeNum() >= 10) {
                    int max = tecpTeclTrans.getObsTypeNum() / 10;
                    for (int i = 0; i < max; i++) {
                        line = lines.get(index++);
                        obsType.append(line.substring(begin, end));
                    }
                }
                for (int i = 0; i < tecpTeclTrans.getObsTypeNum(); i++) {
                    obsTypeList.add(obsType.substring(i * size, (i + 1) * size).trim());
                }
                if ((isVerTow && !obsTypeList.containsAll(GnssContext.OBS_TYPE_A) && !obsTypeList.containsAll(GnssContext.OBS_TYPE_B))
                        || (!isVerTow && !obsTypeList.containsAll(GnssContext.OBS_TYPE_AC) && !obsTypeList.containsAll(GnssContext.OBS_TYPE_BC))) {
                    throw new CustomException(6101, "无匹配类型，无需继续读取");
                }
                tecpTeclTrans.setObsTypeList(obsTypeList);
                continue;
            }
            if (line.contains("END OF HEADER")) {
                break;
            }
        }
        return index + 1;
    }

    /**
     * 获取ObsType值(V3版本)
     *
     * @param line
     * @param obsTypeMap
     */
    public static void getObsTypeVal(String line, Map<String, Double> obsTypeMap) {
        obsTypeMap.put("L1", getMapValue(line, 20, 34));
        obsTypeMap.put("L2", getMapValue(line, 84, 98));
        obsTypeMap.put("C1", getMapValue(line, 4, 18));
        obsTypeMap.put("P2", getMapValue(line, 68, 82));
    }

    /**
     * 获取ObsTye值(B2版本)
     *
     * @param line
     * @param obsType
     * @param num
     * @return
     */
    public static void getObsTypeVal(String line, List<String> obsType, Map<String, Double> obsTypeMap, int num) {
        if (line.length() >= 14) {
            obsTypeMap.put(obsType.get(num), getMapValue(line, 0, 14));
        }
        if (line.length() >= 30) {
            obsTypeMap.put(obsType.get(num + 1), getMapValue(line, 16, 30));
        }
        if (line.length() >= 46) {
            obsTypeMap.put(obsType.get(num + 2), getMapValue(line, 32, 46));
        }
        if (line.length() >= 62) {
            obsTypeMap.put(obsType.get(num + 3), getMapValue(line, 48, 62));
        }
        if (line.length() >= 78) {
            obsTypeMap.put(obsType.get(num + 4), getMapValue(line, 64, 78));
        }
    }

    private static Double getMapValue(String line, int start, int end) {
        String val = line.substring(start, end);
        return StringUtils.isBlank(val) ? 0D : NumberUtils.toDouble(val);
    }

    /**
     * 填充数据
     *
     * @return
     */
    public static TecpTecl getTecpTecl(TecpTeclTrans tecpTeclTrans, Map<String, Double> obsTypeMap, int startNum, String startName, PathFileType pathFileType) {
        //计算TECP和 TECL，此处用了C1,P1,P2和L1,L2五个参数
        double l1 = StringUtils.isBlank(obsTypeMap.get("L1")) ? 0 : obsTypeMap.get("L1"),
                l2 = StringUtils.isBlank(obsTypeMap.get("L2")) ? 0 : obsTypeMap.get("L2"),
                c1 = StringUtils.isBlank(obsTypeMap.get("C1")) ? 0 : obsTypeMap.get("C1"),
                p1 = StringUtils.isBlank(obsTypeMap.get("P1")) ? 0 : obsTypeMap.get("P1"),
                p2 = StringUtils.isBlank(obsTypeMap.get("P2")) ? 0 : obsTypeMap.get("P2");
        if (l1 == 0 || l2 == 0) {
            return null;
        }
        double tecl = 0.0, tecp = 0.0, f1 = GnssContext.F1, f2 = GnssContext.F2, cspeed = GnssContext.CSPEED;
        if (pathFileType == PathFileType.G) {
            if (startNum > GnssContext.TK_NUM.length) {
                return null;
            }
            f1 = (1602 + GnssContext.TK_NUM[startNum] * 9 / 16) * Math.pow(10, 6);
            f2 = (1246 + GnssContext.TK_NUM[startNum] * 7 / 16) * Math.pow(10, 6);
        }
        tecl = (cspeed * l2 / f2 - cspeed * l1 / f1) / 40.28e0 / (1.e0 / f1 / f1 - 1.e0 / f2 / f2) / 1.e16;
        tecl = tecl % 1000.0;
        if (p1 != 0 && p2 != 0) { // TECP == P1*P2
            tecp = (p1 - p2) / 40.28e0 / (1.e0 / f1 / f1 - 1.e0 / f2 / f2) / 1.e16;
            tecp = tecp % 1000.0;
        } else {
            if (c1 == 0 || p2 == 0) {
                return null;
            }
            tecp = (c1 - p2) / 40.28e0 / (1.e0 / f1 / f1 - 1.e0 / f2 / f2) / 1.e16;
            tecp = tecp % 1000.0;
        }
        //保留2位小数
        tecl = Double.valueOf(new DecimalFormat("0.00").format(tecl));
        tecp = Double.valueOf(new DecimalFormat("0.00").format(tecp));

        TecpTecl tecpTecl = new TecpTecl();
        BeanUtils.copyPropertiesExcludeNull(tecpTeclTrans, tecpTecl);
        tecpTecl.setTecp(tecp);
        tecpTecl.setTecl(tecl);
        Double[] singlePath = null;
        // 计算仰角，方位角
        if (pathFileType == PathFileType.N) {
            if (tecpTeclTrans.getNavPath() == null) {
                return null;
            }
            singlePath = PathFiles.checkSinglePath(tecpTeclTrans.getNavPath().get(startNum), tecpTeclTrans.getWeekSeconds(),pathFileType);
            NAzimuthElevation.compute(tecpTeclTrans, singlePath, tecpTecl);
        } else if (pathFileType == PathFileType.G) {
            if (tecpTeclTrans.getGavPath() == null) {
                return null;
            }
            singlePath = PathFiles.checkSinglePath(tecpTeclTrans.getGavPath().get(startNum), tecpTeclTrans.getWeekSeconds(),pathFileType);
            GAzimuthElevation.compute(tecpTeclTrans, singlePath, tecpTecl);
        }else if (pathFileType == PathFileType.C) {
            if (tecpTeclTrans.getCavPath() == null) {
                return null;
            }
            singlePath = PathFiles.checkSinglePath(tecpTeclTrans.getCavPath().get(startNum), tecpTeclTrans.getWeekSeconds(),pathFileType);
            CAzimuthElevation.compute(tecpTeclTrans, singlePath, tecpTecl, startNum);
        }else {
            return null;
        }
        if (tecpTecl.getAzimuth() == null || tecpTecl.getElevation() == null) {
            return null;
        }
        return tecpTecl;
    }
}
